import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'model.dart';

/// 网络请求配置
class NetworkConfig {
  final String baseUrl;
  final Duration connectTimeout;
  final Duration receiveTimeout;
  final Duration sendTimeout;
  final Map<String, String>? defaultHeaders;
  final List<Interceptor>? interceptors;

  const NetworkConfig({
    required this.baseUrl,
    this.connectTimeout = const Duration(seconds: 30),
    this.receiveTimeout = const Duration(seconds: 30),
    this.sendTimeout = const Duration(seconds: 30),
    this.defaultHeaders,
    this.interceptors,
  });
}

/// 网络错误类型
enum NetworkErrorType {
  connectTimeout,
  sendTimeout,
  receiveTimeout,
  response,
  cancel,
  other,
}

/// 自定义网络异常
class NetworkException implements Exception {
  final NetworkErrorType type;
  final String message;
  final int? statusCode;
  final dynamic data;

  NetworkException({
    required this.type,
    required this.message,
    this.statusCode,
    this.data,
  });

  @override
  String toString() {
    return 'NetworkException(type: $type, message: $message, statusCode: $statusCode)';
  }
}

/// 请求日志拦截器
class LogInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    if (kDebugMode) {
      log(' 请求开始');
      log('📍 URL: ${options.uri}');
      log('🔧 Method: ${options.method}');
      log('📋 Headers: ${options.headers}');
      log('📋 Query Parameters: ${options.queryParameters}');
      if (options.data != null) {
        log('📦 Body: ${options.data}');
      }
      if (options.queryParameters.isNotEmpty) {
        log('❓ Query: ${options.queryParameters}');
      }
    }
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    if (kDebugMode) {
      log('✅ 响应成功');
      log('📍 URL: ${response.requestOptions.uri}');
      log('📊 Status: ${response.statusCode}');
      log('📋 Headers: ${response.headers}');
      log('📦 Data: ${response.data}');
    }
    super.onResponse(response, handler);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    if (kDebugMode) {
      log('❌ 请求失败');
      log(' URL: ${err.requestOptions.uri}');
      log('🔧 Method: ${err.requestOptions.method}');
      log('📊 Status: ${err.response?.statusCode}');
      log('💬 Message: ${err.message}');
      log('📦 Data: ${err.response?.data}');
    }
    super.onError(err, handler);
  }
}

/// 错误处理拦截器
class ErrorInterceptor extends Interceptor {
  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    NetworkException networkException;

    switch (err.type) {
      case DioExceptionType.connectionTimeout:
        networkException = NetworkException(
          type: NetworkErrorType.connectTimeout,
          message: '连接超时，请检查网络连接',
          statusCode: err.response?.statusCode,
          data: err.response?.data,
        );
        break;
      case DioExceptionType.sendTimeout:
        networkException = NetworkException(
          type: NetworkErrorType.sendTimeout,
          message: '发送超时，请检查网络连接',
          statusCode: err.response?.statusCode,
          data: err.response?.data,
        );
        break;
      case DioExceptionType.receiveTimeout:
        networkException = NetworkException(
          type: NetworkErrorType.receiveTimeout,
          message: '接收超时，请检查网络连接',
          statusCode: err.response?.statusCode,
          data: err.response?.data,
        );
        break;
      case DioExceptionType.badResponse:
        final statusCode = err.response?.statusCode ?? 0;
        String message = '请求失败';

        if (statusCode >= 400 && statusCode < 500) {
          message = '客户端错误 ($statusCode)';
        } else if (statusCode >= 500) {
          message = '服务器错误 ($statusCode)';
        }

        // 尝试从响应中获取错误信息
        if (err.response?.data is Map<String, dynamic>) {
          final data = err.response!.data as Map<String, dynamic>;
          message = data['message'] ?? data['msg'] ?? message;
        }

        networkException = NetworkException(
          type: NetworkErrorType.response,
          message: message,
          statusCode: statusCode,
          data: err.response?.data,
        );
        break;
      case DioExceptionType.cancel:
        networkException = NetworkException(
          type: NetworkErrorType.cancel,
          message: '请求已取消',
          statusCode: err.response?.statusCode,
          data: err.response?.data,
        );
        break;
      default:
        networkException = NetworkException(
          type: NetworkErrorType.other,
          message: err.message ?? '未知网络错误',
          statusCode: err.response?.statusCode,
          data: err.response?.data,
        );
    }

    handler.reject(
      DioException(
        requestOptions: err.requestOptions,
        error: networkException,
        type: err.type,
        response: err.response,
      ),
    );
  }
}

/// 响应数据转换拦截器
class ResponseInterceptor extends Interceptor {
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 可以在这里统一处理响应数据格式
    // 例如：统一包装响应数据、处理分页等
    super.onResponse(response, handler);
  }
}

/// LaraPress Dio 封装类
class LaraPressDio {
  static LaraPressDio? _instance;
  late Dio _dio;
  NetworkConfig? _config;

  LaraPressDio._();

  /// 单例模式
  static LaraPressDio get instance {
    _instance ??= LaraPressDio._();
    return _instance!;
  }

  /// 初始化 Dio
  void init(NetworkConfig config) {
    _config = config;

    _dio = Dio(
      BaseOptions(
        baseUrl: config.baseUrl,
        connectTimeout: config.connectTimeout,
        receiveTimeout: config.receiveTimeout,
        sendTimeout: config.sendTimeout,
        headers: config.defaultHeaders,
      ),
    );

    // 添加默认拦截器
    _dio.interceptors.addAll([
      LogInterceptor(),
      ErrorInterceptor(),
      ResponseInterceptor(),
      ...?config.interceptors,
    ]);
  }

  /// 获取 Dio 实例
  Dio get dio => _dio;

  /// GET 请求 - 返回单个对象
  Future<LarapressResponse<T>> get<T extends BaseModel>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// GET 请求 - 返回列表对象
  Future<LarapressListResponse<T>> getList<T extends BaseModel>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressListResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// GET 请求 - 返回分页对象
  Future<LarapressPaginatedResponse<T>> getPaginated<T extends BaseModel>(
    String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressPaginatedResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// POST 请求 - 返回单个对象
  Future<LarapressResponse<T>> post<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.post(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// POST 请求 - 返回列表对象
  Future<LarapressListResponse<T>> postList<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.post(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressListResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// POST 请求 - 返回分页对象
  Future<LarapressPaginatedResponse<T>> postPaginated<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.post(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressPaginatedResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// PUT 请求 - 返回单个对象
  Future<LarapressResponse<T>> put<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.put(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// DELETE 请求 - 返回单个对象
  Future<LarapressResponse<T>> delete<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.delete(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// PATCH 请求 - 返回单个对象
  Future<LarapressResponse<T>> patch<T extends BaseModel>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    required T Function(Map<String, dynamic>) fromJson,
  }) async {
    try {
      final response = await _dio.patch(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      final httpModel = _handleResponse(response);
      return LarapressResponse<T>.fromHttpModel(httpModel, fromJson);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// 文件上传
  Future<LarapressHttpModel> uploadFile(
    String path,
    String filePath, {
    String fieldName = 'file',
    Map<String, dynamic>? data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
  }) async {
    try {
      final formData = FormData.fromMap({
        fieldName: await MultipartFile.fromFile(filePath),
        ...?data,
      });

      final response = await _dio.post(
        path,
        data: formData,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
      );
      return _handleResponse(response);
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// 文件下载
  Future<String> downloadFile(
    String url,
    String savePath, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      await _dio.download(
        url,
        savePath,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return savePath;
    } on DioException catch (e) {
      throw e.error is NetworkException
          ? e.error as NetworkException
          : _handleDioError(e);
    }
  }

  /// 处理响应数据
  LarapressHttpModel _handleResponse(Response response) {
    if (response.statusCode == null ||
        response.statusCode! < 200 ||
        response.statusCode! >= 300) {
      throw NetworkException(
        type: NetworkErrorType.response,
        message: 'HTTP ${response.statusCode}',
        statusCode: response.statusCode,
        data: response.data,
      );
    }

    // 如果响应数据是 Map 类型，尝试解析为 LarapressHttpModel
    if (response.data is Map<String, dynamic>) {
      return LarapressHttpModel.fromJson(response.data as Map<String, dynamic>);
    }

    // 否则创建默认的 LarapressHttpModel
    return LarapressHttpModel(
      data: response.data,
      code: response.statusCode,
      msg: '请求成功',
    );
  }

  /// 处理 Dio 错误
  NetworkException _handleDioError(DioException e) {
    return NetworkException(
      type: NetworkErrorType.other,
      message: e.message ?? '网络请求失败',
      statusCode: e.response?.statusCode,
      data: e.response?.data,
    );
  }

  /// 添加拦截器
  void addInterceptor(Interceptor interceptor) {
    _dio.interceptors.add(interceptor);
  }

  /// 移除拦截器
  void removeInterceptor(Interceptor interceptor) {
    _dio.interceptors.remove(interceptor);
  }

  /// 清除所有拦截器
  void clearInterceptors() {
    _dio.interceptors.clear();
  }

  /// 设置认证头
  void setAuthToken(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }

  /// 移除认证头
  void removeAuthToken() {
    _dio.options.headers.remove('Authorization');
  }

  /// 设置基础 URL
  void setBaseUrl(String baseUrl) {
    _dio.options.baseUrl = baseUrl;
  }

  /// 获取当前配置
  NetworkConfig? get config => _config;
}
